package com.example.composeanimation

import android.annotation.SuppressLint
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.calculateTargetValue
import androidx.compose.animation.splineBasedDecay
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.horizontalDrag
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.consumePositionChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.input.pointer.positionChange
import androidx.compose.ui.input.pointer.util.VelocityTracker
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.example.composeanimation.ui.theme.JetpackComposeBasicTheme
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlin.math.absoluteValue
import kotlin.math.roundToInt

/**
 * @author huangzehui
 * @date 11/5/2024 下午8:47 周六
 * @description
 *
 *
 * https://www.bilibili.com/video/BV1ob4y1a7ad?p=60&vd_source=e07cc8cc94eb22bd76722071b03cd199
 */
class MainActivity2 : ComponentActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetpackComposeBasicTheme {
                Demo1()
            }
        }
    }

    @Composable
    private fun Demo1(){
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .height(44.dp)
                .background(Color.Blue)
                .swipeToDismiss {

                }
        ) {
            Text(text = "Hello", color = Color.White)
        }
    }


    /**
     * 手势结合动画
     */
    @SuppressLint("ModifierFactoryUnreferencedReceiver")
    private fun Modifier.swipeToDismiss(onDismissed: () -> Unit) = composed {

        val offsetX = remember {
            Animatable(initialValue = 0f)
        }


        // 创建一个修饰符，用于处理修改元素区域内的光标输入。
        // pointerInput可以调用 PointerInputScope.awaitPointerEventScope,
        // 以安装可以等待PointerEventScope的光标输入处理程序。

        pointerInput(Unit) {
            // 衰减动画通常在投掷姿势后使用，用于计算投掷动画最后的固定位置
            val decay = splineBasedDecay<Float>(this)

            coroutineScope {
                while (true) {
                    // 等待触摸按下事件
                    // awaitPointerEventScope:挂起并安装指针输入块，该块可以等待输入事件并立即响应它们。
                    // awaitFirstDown:读取事件，直到收到第一个down。
                    val pointerId = awaitPointerEventScope {
                        awaitFirstDown().id
                    }

                    // 记录速度的
                    val velocityTracker = VelocityTracker()

                    // 等待拖动事件
                    awaitPointerEventScope {
                        // 监听水平滚动
                        horizontalDrag(pointerId) { pointerInputChange: PointerInputChange ->
                            val horizontalDragOffset =offsetX.value+ pointerInputChange.positionChange().x

                            // 启动协程，执行动画
                            launch {
                                offsetX.snapTo(horizontalDragOffset)
                            }

                            // 记录滑动的位置
                            velocityTracker.addPosition(
                                pointerInputChange.uptimeMillis,
                                pointerInputChange.position
                            )

                            // 消除掉手势事件，而不是传递给外部
                            if (pointerInputChange.positionChange() != Offset.Zero) {
                                pointerInputChange.consume()
                            }
//                            pointerInputChange.consumePositionChange()
                        }
                    }

                    // 拖动完成，计算投掷的速度
                    val velocity = velocityTracker.calculateVelocity().x

                    // 我们需要计算投掷的最终位置。以决定是将元素滑回原始位置，还是将其滑开并调用回调。
                    val targetOffsetX = decay.calculateTargetValue(offsetX.value, velocity)

                    offsetX.updateBounds(
                        lowerBound = -size.width.toFloat(),
                        upperBound = size.width.toFloat()
                    )

                    launch {
                        if (targetOffsetX.absoluteValue <= size.width) {
                            // 滑回来
                            offsetX.animateTo(targetValue = 0f, initialVelocity = velocity)
                        } else {
                            // 启动衰减动画
                            offsetX.animateDecay(velocity, decay)
                            onDismissed()
                        }
                    }
                }
            }
        }.offset {
            IntOffset(offsetX.value.roundToInt(), 0)
        }
    }

}